package yto.freemarker.springcloud.controller;

import com.google.common.collect.Lists;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import yto.freemarker.springcloud.entity.User;

import javax.jws.soap.SOAPBinding;
import java.util.ArrayList;
import java.util.List;

/**
 * @author dongxing
 * @create 2018-02-27 22:16
 **/
@RestController
@AllArgsConstructor(onConstructor = @_(@Autowired))
public class UserController {

    private final DiscoveryClient discoveryClient;

    private final RestTemplate restTemplate;

    /**
     * 方式一：通过ip地址来实现
     *
     * @param id
     * @return
     */
    @GetMapping("/user/{id}")
    public User findById(@PathVariable String id) {
        //服务提供者的spring.application.name的值
        String serviceId = "service-provider";
        //本处是通过应用名称来获取的，可能会有多个实例，所以用集合来存储(同一个应用名对应不同的ip地址)
        List<ServiceInstance> instances = this.discoveryClient.getInstances(serviceId);
        if (instances.isEmpty()) {
            return null;
        }
        // 为了演示，在这里只获取一个实例
        ServiceInstance serviceInstance = instances.get(0);
        String url = serviceInstance.getHost() + ":" + serviceInstance.getPort();
        return this.restTemplate.getForObject("http://" + url + "/user/" + id, User.class);

    }

    /**
     * 方式二：通过服务名来实现
     * 需要引入ribbon的依赖
     * 并且在restTemplate上面添加@LoadBalanced来实现
     *
     * @param id
     * @return
     */
    @GetMapping("/user/1/{id}")
    public User findById1(@PathVariable String id) {
        //服务提供者的spring.application.name的值
        String serviceId = "service-provider";
        return this.restTemplate.getForObject("http://" + serviceId + "/user/" + id, User.class);
    }

    /**
     * 测试Hystrix的保护机制
     *
     * @return
     */
    @GetMapping("/user/all/{id}")
    @HystrixCommand(fallbackMethod = "fallBackMethod")
    public List<User> findAll(Long id) {
        //服务提供者的spring.application.name的值
        String serviceId = "service-provider";
        return this.restTemplate.getForObject("http://" + serviceId + "/user/all", List.class);
    }

    private List<User> fallBackMethod(Long id) {
        List<User> list = Lists.newArrayList();
        list.add(User.builder().name("1").build());
        list.add(User.builder().name("2").build());
        list.add(User.builder().name("3").build());
        return list;
    }

    /**
     * 测试Hystrix的线程机制
     *
     * @return
     */
    @GetMapping("/users/1")
    @HystrixCommand(fallbackMethod = "fallBackMethod", commandProperties = {@HystrixProperty(name = "execution.isolation.strategy", value = "SEMAPHORE")})
    public List<User> findAll1(Long id) {
        //服务提供者的spring.application.name的值
        String serviceId = "service-provider";
        return this.restTemplate.getForObject("http://" + serviceId + "/user/all", List.class);
    }

}
